/**
 * Created with JetBrains WebStorm.
 * User: Steven
 * Date: 25-4-13
 * Time: 20:07
 * To change this template use File | Settings | File Templates.
 */

/**
 * Stores all Character information. Holds a gender, race, birthsign and a class. Configure the levelUpEvent
 * for processing automatic level-ups of the Character.
 *
 * @param gender
 * @param race
 * @param birthsign
 * @param characterClass
 * @constructor
 */
function Character(gender, race, birthsign, characterClass)
{
    this.id = -1;   // ID for database syncing
    this.key = "Unknown";  // Key for database snycing
    this.gender = gender;
    this.race = race;
    this.birthsign = birthsign;
    this.class = characterClass;
    this.skillSet = new SkillSet(this);
    this.attributeSet = new AttributeSet(this);

    // Events
    this.levelUpEvent = function(leveledSkills){};

    // Configure Attribute-Skill relations
    this.setupStatRelations();
}

/**
 * Calculates the level of the Character.
 * @returns {number} The level of the character. Round number (1,2,3...)
 */
Character.prototype.calculateLevel = function()
{
    // Obtain all major skills
    var majorSkills = [];
    var majorSkillTypeKeys = this.class.getMajorSkillTypes();
    for(var i = 0; i < majorSkillTypeKeys.length; i++)
    {
        var majorSkill = this.skillSet.getSkill(majorSkillTypeKeys[i]);
        majorSkills.push(majorSkill);
    }

    // Calculate the total progress level
    var combinedLevel = 0;
    for(var j = 0; j < majorSkills.length; j++)
    {
        var skill = majorSkills[j];
        combinedLevel += skill.level;
    }
    return (combinedLevel / 10) + 1;
};

/**
 * Calculates the progress to the next level in percentages.
 * @returns {number} The level progress percentage. Ranges from 0 to 100.
 */
Character.prototype.calculateLevelProgress = function()
{
    // Obtain all major skills
    var majorSkills = [];
    var majorSkillTypeKeys = this.class.getMajorSkillTypes();
    for(var i = 0; i < majorSkillTypeKeys.length; i++)
    {
        var majorSkill = this.skillSet.getSkill(majorSkillTypeKeys[i]);
        majorSkills.push(majorSkill);
    }

    // Calculate the total progress level
    var progressLevel = 0;
    for(var j = 0; j < majorSkills.length; j++)
    {
        var skill = majorSkills[j];
        progressLevel += skill.progressLevel;
    }
    return (progressLevel / 10) * 100;
};

/**
 * Verifies the leveling progress, and levels the Character up if the level progress is 100%.
 */
Character.prototype.verifyLevelProgress = function()
{
    if(this.calculateLevelProgress() == 100)
        this.levelUp();
};

/**
 * Levels the Character up by calling levelUp on all skills in the Character's SkillSet.
 */
Character.prototype.levelUp = function()
{
    var leveledSkills = [];
    var skills = this.skillSet.getSkills();
    for(var i = 0; i < skills.length; i++)
    {
        if(skills[i].levelUp())
            leveledSkills.push(skills[i]);
    }
    this.levelUpEvent(leveledSkills);
};

/**
 * Configures the relations between Attributes and Skills
 */
Character.prototype.setupStatRelations = function()
{
    // Strength
    var attrStr = this.attributeSet.getAttribute(AttributeTypes.strength);
    attrStr.addGoverningSkill(this.skillSet.getSkill(SkillTypes.blade));
    attrStr.addGoverningSkill(this.skillSet.getSkill(SkillTypes.blunt));
    attrStr.addGoverningSkill(this.skillSet.getSkill(SkillTypes.handtohand));

    // Intelligence
    var attrInt = this.attributeSet.getAttribute(AttributeTypes.intelligence);
    attrInt.addGoverningSkill(this.skillSet.getSkill(SkillTypes.alchemy));
    attrInt.addGoverningSkill(this.skillSet.getSkill(SkillTypes.conjuration));
    attrInt.addGoverningSkill(this.skillSet.getSkill(SkillTypes.mysticism));

    // Willpower
    var attrWill = this.attributeSet.getAttribute(AttributeTypes.willpower);
    attrWill.addGoverningSkill(this.skillSet.getSkill(SkillTypes.alteration));
    attrWill.addGoverningSkill(this.skillSet.getSkill(SkillTypes.destruction));
    attrWill.addGoverningSkill(this.skillSet.getSkill(SkillTypes.restoration));

    // Agility
    var attrAgi = this.attributeSet.getAttribute(AttributeTypes.agility);
    attrAgi.addGoverningSkill(this.skillSet.getSkill(SkillTypes.marksmanship));
    attrAgi.addGoverningSkill(this.skillSet.getSkill(SkillTypes.security));
    attrAgi.addGoverningSkill(this.skillSet.getSkill(SkillTypes.sneak));

    // Speed
    var attrSpd = this.attributeSet.getAttribute(AttributeTypes.speed);
    attrSpd.addGoverningSkill(this.skillSet.getSkill(SkillTypes.acrobatics));
    attrSpd.addGoverningSkill(this.skillSet.getSkill(SkillTypes.athletics));
    attrSpd.addGoverningSkill(this.skillSet.getSkill(SkillTypes.lightarmor));

    // Endurance
    var attrEnd = this.attributeSet.getAttribute(AttributeTypes.endurance);
    attrEnd.addGoverningSkill(this.skillSet.getSkill(SkillTypes.armorer));
    attrEnd.addGoverningSkill(this.skillSet.getSkill(SkillTypes.block));
    attrEnd.addGoverningSkill(this.skillSet.getSkill(SkillTypes.heavyarmor));

    // Personality
    var attrPers = this.attributeSet.getAttribute(AttributeTypes.personality);
    attrPers.addGoverningSkill(this.skillSet.getSkill(SkillTypes.illusion));
    attrPers.addGoverningSkill(this.skillSet.getSkill(SkillTypes.mercantile));
    attrPers.addGoverningSkill(this.skillSet.getSkill(SkillTypes.speechcraft));
};

Character.prototype.toJSON = function()
{
    var charArray = {}; // Associative array

    // Fill in general information
    charArray["gender"] = indexOfValue(Gender, this.gender);
    charArray["race"] = this.race.id;
    charArray["birthsign"] = this.birthsign.id;
    charArray["class"] = this.class.id;

    // If there is a custom class, declare it in the Character array (custom classes have id = -1)
    if(this.class.id < 0)
    {
        // Define the custom Class favored Attributes
        var classArray = {};
        classArray["name"] = this.class.name;
        classArray["specialization"] = this.class.specialization.id;
        classArray["favoredAttributeOne"] = this.attributeSet.getAttribute(this.class.favoredAttributeOne).id;
        classArray["favoredAttributeTwo"] = this.attributeSet.getAttribute(this.class.favoredAttributeTwo).id;

        // Configure the major Skills string
        var majorSkills = "";
        var majorSkillTypes = this.class.getMajorSkillTypes();
        for(var i = 0; i < majorSkillTypes.length; i++)
        {
            var skillType = majorSkillTypes[i];
            var skill = this.skillSet.getSkill(skillType);
            if(i > 0)
                majorSkills += ",";
            majorSkills += skill.id;
        }
        classArray["majorSkills"] = majorSkills;
        charArray["customClass"] = classArray;
    }

    // Configure the SkillSet -- Disabled, all stats are 0,0 anyway at Character creation
//    var skillSetArray = {};
//    var skills = this.skillSet.getSkills();
//    for(var i = 0; i < skills.length; i++)
//    {
//        var skill = skills[i];
//        skillSetArray[skill.skillTypeKey] = skill.level + "," + skill.progressLevel;
//    }
//    charArray["skillSet"] = skillSetArray;

    return JSON.stringify(charArray);
};

function indexOfValue(array, value)
{
    var keys = Object.keys(array);
    for(var i = 0; i < keys.length; i++)
    {
        if(array[keys[i]] == value)
            return i;
    }
    return -1;
}

/**
 * Gender enumeration
 * @type {{male: string, female: string}}
 */
var Gender = { "male":"Male", "female":"Female" };
Object.freeze(Gender);